package foo;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolServer implements Runnable {
	private final int				serverPort;
	private final Object			syncLock	= new Object();
	private Thread					runningThread;
	private ServerSocket			serverSocket;
	private boolean					isStopped;
	private int						clientCount;
	private final ExecutorService	threadPool	= Executors.newFixedThreadPool(10);

	public ThreadPoolServer(int aPort) {
		this.serverPort = aPort;
		this.clientCount = 0;
	}

	public void run() {
		synchronized (syncLock) {
			this.runningThread = Thread.currentThread();
		}

		openServerSocket();

		while (!this.stopped()) {
			Socket clientSocket = null;

			try {
				clientSocket = this.serverSocket.accept();
			} catch (IOException e) {
				if (this.stopped()) {
					System.out.println("Server Stopped");
					return;
				}

				throw new RuntimeException("Unable to accept connection", e);
			}
			System.err.println("Processing client:" + ++clientCount);
			this.threadPool.execute(new WorkerRunnable(clientSocket, "ThreadPool Server:" + clientCount));
		}

		System.out.println("Server stopped");
	}

	private synchronized boolean stopped() {
		return this.isStopped;
	}

	public synchronized void stop() {
		this.isStopped = true;
		try {
			this.serverSocket.close();
		} catch (IOException e) {
			throw new RuntimeException("Unable to close server socket", e);
		}
	}

	private void openServerSocket() {
		try {
			this.serverSocket = new ServerSocket(this.serverPort);
			System.out.println("Server listening to " + this.serverPort);
		} catch (IOException e) {
			throw new RuntimeException("Unable to bind to port:" + this.serverPort, e);
		}
	}

}
